﻿using Elfie.Serialization;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using PesticideManage.API.Data;
using PesticideManage.API.Models;
using PesticideManage.API.Services.Identity.UserAggregate;
using PesticideManage.API.Services.JWT;
using Shang.Sms;
using System.Linq.Expressions;

namespace PesticideManage.API.Controllers;
[Route("api/[controller]")]
[ApiController]
[AllowAnonymous]
public class LoginController : ControllerBase
{
    private readonly PesticideContext _context;
    private readonly ISmsService _smsService;
    private readonly IAuthTokenService _authTokenService;

    public LoginController(PesticideContext context, ISmsService smsService, IAuthTokenService authTokenService)
    {
        _context = context;
        _smsService = smsService;
        _authTokenService = authTokenService;
    }
    private async Task<User?> GetUserAsync(Expression<Func<User, bool>> predicate)
    {
        var user = await _context.Users.AsNoTracking().Where(predicate).Include(u => u.IDCard).Include(u => u.Enterprise).Include(u => u.Roles).ThenInclude(r => r.Menus).ThenInclude(m => m.Children).AsSplitQuery().FirstOrDefaultAsync();
        return user;
    }
    /// <summary>
    /// 登录
    /// </summary>
    /// <param name="userDTO"></param>
    /// <returns></returns>
    [HttpPost()]
    public async Task<ActionResult<LoginDTO>> Login(UserDTO userDTO)
    {
        // var user = await GetUserAsync(u => u.Name == userDTO.Name);
        //var user = await GetUserAsync(u => u.Name == userDTO.Name, u => new User(u.Id, u.Password) { Name = u.Name, MobileNumber = u.MobileNumber });
        //var user = await _context.Users.AsNoTracking().Include(u => u.Roles).AsSplitQuery().Where(u => u.Name == userDTO.Name).FirstOrDefaultAsync();
        var user = await _context.Users.Where(u => u.Name == userDTO.Name).FirstOrDefaultAsync();
        if (user is null || !user.VerifyPassword(userDTO.Password))
        {
            return BadRequest("帐号密码错误。");
        }
        AuthTokenDTO token = await _authTokenService.CreateAuthTokenAsync(user);
        //var roles = await _context.Roles.AsNoTracking().Where(r => r.Users!.Any(u => u.Id == user.Id)).ToListAsync();
        //user.Roles = roles;
        //var t1 = _context.Users.Entry(user).Collection(u => u.Roles).LoadAsync();
        //var t2 = _context.Users.Entry(user).Reference(u => u.IDCard).LoadAsync();
        //var t3 = _context.Users.Entry(user).Navigation(nameof(user.Enterprise)).LoadAsync();
        //await Task.WhenAll(t1, t2, t3);
        //await _context.Users.Entry(user).Navigation(nameof(user.Enterprise)).LoadAsync();
        //await _context.Users.Entry(user).Reference(u => u.Roles).LoadAsync();
        await _context.Users.Entry(user).Collection(u => u.Roles).Query().AsSplitQuery().LoadAsync();

        await _context.Entry(user).Reference(u => u.IDCard).LoadAsync();

        return Ok(new LoginDTO { Token = token, User = user });
    }
    [HttpPost("[action]")]
    public async Task<ActionResult<LoginDTO>> UseSMS(UserDTO userDTO)
    {
        if (!_smsService.VerifyCode(userDTO.MobileNumber, userDTO.SmsVCode))
        {
            return BadRequest("验证码错误");
        }
        //var user = await _context.Users.FirstOrDefaultAsync(u => u.MobileNumber == userDTO.MobileNumber);
        var user = await GetUserAsync(u => u.MobileNumber == userDTO.MobileNumber);
        if (user is null)
        {
            throw new NullReferenceException(nameof(user));
        }
        var authTokenDTO = await _authTokenService.CreateAuthTokenAsync(user);
        return Ok(new LoginDTO { Token = authTokenDTO, User = user });
    }
    /// <summary>
    /// 刷新令牌
    /// </summary>
    /// <param name="authTokenDTO"></param>
    /// <returns></returns>
    [HttpPost("[action]")]
    public async Task<ActionResult<AuthTokenDTO>> RefreshAuthTokenAsync(AuthTokenDTO authTokenDTO)
    {
        var tokenDTO = await _authTokenService.RefreshAuthTokenAsync(authTokenDTO);
        return Ok(tokenDTO);
    }
}
